package command;

import interfaces.CommandTypeInfo;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.ArrayList;

import annotations.AsCommand;

public class UniversalCommandProcessor {

	private BufferedReader shellReader = new BufferedReader(
			new InputStreamReader(System.in));
	@SuppressWarnings("unused")
	private PrintWriter shellWriter = new PrintWriter(System.out);
	private Object target;
	private Class<?> interf;
	private ArrayList<CommandTypeInfo> commandtypeinfos;
	private boolean gathered = false;

	public UniversalCommandProcessor(Object target, Class<?> interf) {
		this.target = target;
		this.interf = interf;
		this.commandtypeinfos = new ArrayList<>();
	}

	private void gatherCommandTypeInfoObjects() {
		// create this.commandtypeinfos and fill it with commands (enum or some
		// shit)
		if (!gathered) {
			Method[] methods = interf.getMethods();
			// this.commandtypeinfos = new CommandTypeInfo[methods.length];
			for (int i = 0; i < methods.length; i++) {

				// Annotation[] methodAnnotations = methods[i].getAnnotations();
				// create commadtypeinfos array

				AsCommand ascommandAnnotation = methods[i]
						.getAnnotation(AsCommand.class);

				this.commandtypeinfos.add(new CommandType(
						(String) ascommandAnnotation.commandShellCommando(),
						(String) ascommandAnnotation.description(),
						(Object) this.target, methods[i],
						(Class<?>[]) methods[i].getParameterTypes()));
			}
			this.gathered = true;
		}

	}

	@SuppressWarnings("unused")
	private CommandTypeInfo createSimypleCommandDesc(String name) {

		return null;
	}

	public void process() throws Throwable {
		gatherCommandTypeInfoObjects();
		CommandScanner commandScanner = new CommandScanner(commandtypeinfos,
				shellReader, interf);

		while (true) {

			Command command = new Command();
			try {
				commandScanner.fillInCommandDesc(command);
			} catch (Exception e1) {
				throw e1;
			}

			if (commandScanner.getCommand().equals("help"))
				this.help();
			else if (commandScanner.getCommand().equals("exit"))
				this.exit();
			else {

				try {
					@SuppressWarnings("unused")
					Object result = command.execute();
				} catch (Exception e) {

					throw e;
				}

			}
		}

	}

	// spackt
	public void help() {
		for (CommandTypeInfo com : this.commandtypeinfos) {
			System.out.println(com.getCommandName() + " "
					+ com.getCommandDescription());
		}
	}

	public void exit() {
		System.exit(0);
	}

}
